/*******************************************************************************
 * (c) Copyright 2017 lvxi. All Rights Reserved.
 ******************************************************************************/

package edu.jxufe.nb112.common.web.aop.aspect;


import edu.jxufe.nb112.common.web.aop.annotation.CRSFTokenVerify;
import edu.jxufe.nb112.common.web.servlet.tags.CRSFTokenTag;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by lvxi on 2017/2/16.
 */
@Aspect
public class CRSFTokenAspect implements Ordered {
    private Logger logger = LoggerFactory.getLogger(CRSFTokenAspect.class.getName());
    /**
     * 处理数据校验，异常将消息返回给前台，json格式
     *
     * @param pjp
     * @return
     * @throws Throwable
     */
    @Around("@annotation(edu.jxufe.nb112.common.web.aop.annotation.CRSFTokenVerify)")
    public Object poress(ProceedingJoinPoint pjp) throws Throwable {

        Method currentMethod = getCurrentMethod(pjp);
        Object[] args = pjp.getArgs();
        CRSFTokenVerify crsfTokenVerify = AnnotationUtils.findAnnotation(currentMethod, CRSFTokenVerify.class);
        String ids = crsfTokenVerify.value();
        Object retValue=null; //返回的值

        if(StringUtils.isNoneEmpty(ids)){
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String[] idsStr = ids.split(",");
            boolean isVerify = true;
            for(String id : idsStr){
                if(!CRSFTokenTag.validate(request,id)){
                    isVerify=false;
                    break;
                };
            }

            if(!isVerify){
                //非法
                if(!crsfTokenVerify.errorStop()){
                    retValue= pjp.proceed();
                }
                else {
                    //不执行controller
                    if (isAjax(currentMethod)){
                        Map msg = new HashMap();
                        msg.put("success",false);
                        msg.put("msg","页面过期");
                        ResponseEntity responseEntity = ResponseEntity.ok(msg);
                        return  responseEntity;
                    }
                    else {

                        String errorPage = crsfTokenVerify.errorPage();
                        logger.debug("跳转 => "+errorPage);
                        return errorPage;
                    }

                }

            }else {
                retValue= pjp.proceed();
            }

        }else {
            retValue= pjp.proceed();
        }


        return retValue;
    }

    /**
     * 通过切点获取当前方法
     * @param pjp
     * @return
     * @throws NoSuchMethodException
     * @throws IllegalArgumentException
     */
    private Method getCurrentMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException, IllegalArgumentException {
        Signature sig = pjp.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Object target = pjp.getTarget();
        Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
        return currentMethod;
    }

    /**
     * 增强顺序，越小越优先
     *
     * @return
     */
    public int getOrder() {
        return 1;
    }


    /**
     * 通过注解ResponseBody,判断是否 ajax 调用
     *
     * @param method
     * @return
     */
    private boolean isAjax(Method method) {
        ResponseBody responseBodyAnn = AnnotationUtils.findAnnotation(method, ResponseBody.class);
        return responseBodyAnn != null;
    }

}
